package org.example.audio;

/**
 * @author zehua
 * @date 2023/11/8 16:11
 * @Description TODO FFT(傅立叶变换) 对比音频 需要测试
 * @since V1.1.0
 */
import org.bytedeco.javacv.FFmpegFrameGrabber;
import org.bytedeco.javacv.Frame;
import org.bytedeco.javacv.FrameGrabber;
import org.bytedeco.opencv.opencv_core.Mat;
import org.bytedeco.opencv.opencv_core.Scalar;

import java.nio.ShortBuffer;

import static org.bytedeco.opencv.global.opencv_core.*;

public class AudioFFTComparator {


    public static void main(String[] args) {
        // 有两个音频文件
        String audioFile1 = "E:\\test\\video\\1.mp3";
        String audioFile2 = "E:\\test\\video\\testAudio_2023-11-081654652.mp3";

        // 获取音频文件的FFT
        Mat fft1 = getAudioFFT(audioFile1);
        Mat fft2 = getAudioFFT(audioFile2);

        // 比较两个FFT的相似度
        double similarity = compareFFTs(fft1, fft2);

        System.out.println("Similarity: " + similarity);
    }


    private static Mat getAudioFFT(String audioFilePath) {
        // 使用FFmpeg读取音频文件
        FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(audioFilePath);
        try {
            grabber.start();

            Frame frame;
            while ((frame = grabber.grabSamples()) != null) {
                ShortBuffer samples = (ShortBuffer) frame.samples[0].position(0);
                float[] audioFloats = new float[samples.limit()];
                for (int i = 0; i < samples.limit(); i++) {
                    audioFloats[i] = samples.get(i);
                }

                // 计算FFT
                Mat audioMat = new Mat(audioFloats);
                Mat complexImage = new Mat();
                dft(audioMat, complexImage, DFT_REAL_OUTPUT, 0);

                // 只处理第一个FFT结果
                return complexImage;
            }
        } catch (FrameGrabber.Exception e) {
            e.printStackTrace();
        } finally {
            try {
                grabber.stop();
            } catch (FrameGrabber.Exception e) {
                e.printStackTrace();
            }
        }
        return new Mat();
    }

    private static double compareFFTs(Mat fft1, Mat fft2) {
        // 使用OpenCV的方法比较两个FFT结果的相似度
        Mat diff = new Mat();
        absdiff(fft1, fft2, diff); // 计算差异的绝对值
        Scalar diffSum = sumElems(diff); // 对所有元素求和
        double totalDiff = diffSum.get(0); // 总差异

        // 使用某种方式计算相似度
        // 这里是一个非常简单的相似度评分，它只是基于总差异的倒数
        // 实际应用中需要更复杂的方法
        return 1.0 / (1.0 + totalDiff);
    }
}